﻿using NineSeas.Models;
using NineSeas.Services;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using NineSeas.ViewModels;
using NineSeas.Extensions;
using Orchard.Services;
using Orchard.FileSystems.Media;

namespace NineSeas.Api
{
    [Authorize]
    public class BookController : ApiController
    {
        private readonly IOrchardServices _services;
        private readonly IAuthenticationService _authenticationService;
        private readonly IBookService _bookService;
        private readonly IClock _clock;
        private readonly IStorageProvider _storageProvider;
        public BookController(IAuthenticationService authenticationService,
                IBookService bookService,
                IOrchardServices services,
                IClock clock,
                IStorageProvider storageProvider)
        {
            _authenticationService = authenticationService;
            _bookService = bookService;
            _services = services;
            _clock = clock;
            _storageProvider = storageProvider;
        }

        // GET api/<controller>
        public HttpResponseMessage Get(string expression = "", 
            string category = "", 
            int? authorId = null,
            string orderBy = "name", 
            string orderDirection = "asc",
            int pageIndex = 0,
            int pageSize = 10,
            int? bookType = null,
            bool isMod = false)
        {
            var search = new BookSearchViewModel {
                Expression = expression,
                Category = category,
                OrderBy = orderBy,
                OrderDirection = orderDirection,
                BookType = (BookTypeEnum?) bookType
            };

            search.SetOptions(new BookSearchViewModel.SearchOptions
            {
                ForEdit = false
            });

            var user = _authenticationService.GetAuthenticatedUser();

            // unauthenticated
            if (user == null) return Request.CreateResponse<GeneralResult>(HttpStatusCode.Forbidden, new GeneralResult
            {
                Code = new List<MessageDefinition>() { MessageDefinitions.INSUFFICIENT_PRIVILEDGE }.Select(m => m.Code),
                Message = String.Empty
            });

            search.AuthorId = authorId;

            var paging = new PaginationInfo {
                CurrentPage = pageIndex,
                PageSize = pageSize
            };

            return Request.CreateResponse<BookListViewModel>(HttpStatusCode.Accepted, new BookListViewModel
            {
                Books = _bookService.Search(search, paging, VersionOptions.Latest),
                Search = search,
                Paging = paging
            });
        }

        // GET api/<controller>/5
        public BookSummaryViewModel Get(int id)
        {
            var bookPart = _services.ContentManager.Get<BookPart>(id, VersionOptions.Latest);
            return bookPart != null ? new BookSummaryViewModel(bookPart) : null;
        }

        // POST api/<controller>
        [HttpPost]
        public HttpResponseMessage Post([FromBody]BookSummaryViewModel book)
        {
            var validationResults = new List<MessageDefinition>();
            if (!_services.Authorizer.Authorize(Permissions.AddBooks))
            {
                validationResults.Add(MessageDefinitions.INSUFFICIENT_PRIVILEDGE);
                return Request.CreateResponse<GeneralResult>(HttpStatusCode.Forbidden, new GeneralResult
                {
                    Code = validationResults.Select(m => m.Code),
                    Message = String.Empty
                });
            }

            validationResults.AddRange(ValidateBook(book, book.Id == null));

            bool success = validationResults.Any(m => m.Type == MessageDefinitions.Types.Error);

            if (success)
            {
                validationResults.AddRange(Save(book));
                success = validationResults.Any(m => m.Type == MessageDefinitions.Types.Error);
            }
            
            if (success)
            {
                return Request.CreateResponse<BookSummaryViewModel>(HttpStatusCode.Accepted, book);
            }
            else
            {
                return Request.CreateResponse<GeneralResult>(HttpStatusCode.Conflict, new GeneralResult {
                    Code = validationResults.Select(m => m.Code),
                    Message = String.Empty
                });
            }

        }

        #region Private Methods
        private IEnumerable<MessageDefinition> Save(BookSummaryViewModel book)
        {
            var messages = new List<MessageDefinition>();
            var bookPart = book.Id == null ? _services.ContentManager.Create<BookPart>("Book", VersionOptions.Draft, b => b.CreatedDate = _clock.UtcNow)
                : _services.ContentManager.Get<BookPart>(book.Id.Value, VersionOptions.DraftRequired);

            bookPart.Name = book.Name;
            bookPart.NameOnUrl = book.NameOnUrl;
            bookPart.Introduction = book.Introduction;
            bookPart.LastUpdatedDate = _clock.UtcNow;
            if (!String.IsNullOrEmpty(book.ImageStoragePath)
                    && String.Compare(bookPart.ImageStoragePath, book.ImageStoragePath) != 0)
            {
                bookPart.ImageUrl = _storageProvider.GetPublicUrl(book.ImageStoragePath);
            }

            bookPart.ImageStoragePath = book.ImageStoragePath;


            messages.Add(_bookService.SaveTags(bookPart, book.Tags));

            _bookService.SaveCategories(bookPart, book.Categories);
            messages.Add(_bookService.ProcessPublication(bookPart, book.Publishing));

            return messages;
        }
        private IEnumerable<MessageDefinition> ValidateBook(BookSummaryViewModel book, bool isNew)
        {
            var messages = new List<MessageDefinition>();

            if (String.IsNullOrWhiteSpace(book.Name)) messages.Add(MessageDefinitions.BOOK_NAME_REQUIRED);
            else if (Constants.DisalowedChars.Intersect(book.Name).Any()) messages.Add(MessageDefinitions.BOOK_NAME_CONTAINS_SPECIAL_CHARS);

            if (String.IsNullOrWhiteSpace(book.NameOnUrl)) messages.Add(MessageDefinitions.BOOK_NAMEONURL_REQUIRED);
            else if (_services.ContentManager.Query<BookPart, BookPartRecord>()
                    .ForVersion(VersionOptions.Published)
                    .Where(b => b.NameOnUrl == book.NameOnUrl && (isNew || book.Id != b.ContentItemRecord.Id))
                    .Count() > 0) messages.Add(MessageDefinitions.BOOK_NAMEONURL_REQUIRED);
            else if (Constants.DisalowedChars.Intersect(book.NameOnUrl).Any()) messages.Add(MessageDefinitions.BOOK_NAMEONURL_CONTAINS_SPECIAL_CHARS);

            if (String.IsNullOrWhiteSpace(book.Introduction)) messages.Add(MessageDefinitions.BOOK_INTRODUCTION_REQUIRED);

            if (book.Categories == null || !book.Categories.Any()) messages.Add(MessageDefinitions.BOOK_CATEGORY_REQUIRED);
            if (String.IsNullOrWhiteSpace(book.ImageStoragePath)) messages.Add(MessageDefinitions.BOOK_COVER_REQUIRED);
            return messages;
        }
        #endregion
    }
}